package org.me.marble;

import java.nio.*;

import android.os.Vibrator;
import java.util.ArrayList;
import android.content.Context;
import javax.microedition.khronos.opengles.GL10;

/**
 *
 * @author tungi
 */

public class Gate extends AvailableObject{
    private int flag=1;
    private int res_tube,res;
    private boolean incr=true;
    private float delta=0.0f,angle=0.0f;
    private FloatBuffer leftPointBuffer,leftTextureBuffer,
                        rightPointBuffer,rightTextureBuffer;

    public Gate(int id){
        super(id);
    }

    @Override
    public void effect(GameRenderer _renderer,MoveMarble _mm){
        _mm.modifySpeed(0.1);
        if(OptionsLibrary.vibrate){
            Vibrator vibrator=(Vibrator)GameActivity.game.
                                        getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(new long[]{200,200,200,200},-1);
        }
        _renderer.addRunnable(timerTypes.endlevel.ordinal(),3000);
    }

    @Override
    public void init(){
        if(OptionsLibrary.objects_quality.equals("low")){
            res=10;res_tube=5;}
        else if(OptionsLibrary.objects_quality.equals("medium")){
            res=20;res_tube=10;}
        else if(OptionsLibrary.objects_quality.equals("high")){
            res=30;res_tube=15;}

        createBuffer(-1);//left
        createBuffer(1);//right

        color=new MyColor();
        color.setAmbient(new float[]{1.0f,1.0f,1.0f,1.0f});
        color.setDiffuse(new float[]{1.0f,1.0f,1.0f,1.0f});
        color.setSpecular(new float[]{0.6f,0.6f,0.6f,1.0f});
        color.setEmission(new float[]{0.1f,0.1f,0.1f,1.0f});
        color.setShininess(1.0f);

    }

    public void createBuffer(int dir){
        double a1,a2,b1,b2,c,k;
        float rad=1.25f,tube=0.1f;

        ArrayList<Float> tex=new ArrayList<Float>();
        ArrayList<Float> torus=new ArrayList<Float>();

        for(int j=0;j<res/2;++j){
            if(dir==1)
                k=res/4-j;
            else
                k=res/4+j;

            for(int i=0;i<=res_tube;++i){
                a1=(rad+tube*Math.cos(i*2*Math.PI/res_tube))*Math.cos((k-dir)*2*Math.PI/res);
                b1=(rad+tube*Math.cos(i*2*Math.PI/res_tube))*Math.sin((k-dir)*2*Math.PI/res);
                a2=(rad+tube*Math.cos(i*2*Math.PI/res_tube))*Math.cos(k*2*Math.PI/res);
                b2=(rad+tube*Math.cos(i*2*Math.PI/res_tube))*Math.sin(k*2*Math.PI/res);
                c=tube*Math.sin(i*2*Math.PI/res_tube);

                if(dir==1){
                    torus.add((float)a1);
                    torus.add((float)b1);
                    torus.add((float)c);

                    tex.add((float)i/res_tube);
                    tex.add((float)k-dir);

                    torus.add((float)a2);
                    torus.add((float)b2);
                    torus.add((float)c);

                    tex.add((float)i/res_tube);
                    tex.add((float)k);
                }
                else{
                    torus.add((float)a2);
                    torus.add((float)b2);
                    torus.add((float)c);

                    tex.add((float)i/res_tube);
                    tex.add((float)k);

                    torus.add((float)a1);
                    torus.add((float)b1);
                    torus.add((float)c);

                    tex.add((float)i/res_tube);
                    tex.add((float)k-dir);
                }
            }
        }
        
        if(dir==1){
            rightTextureBuffer=BufferFactory.MakeFloatBuffer(tex);
            rightPointBuffer=BufferFactory.MakeFloatBuffer(torus);
        }
        else{
            leftTextureBuffer=BufferFactory.MakeFloatBuffer(tex);
            leftPointBuffer=BufferFactory.MakeFloatBuffer(torus);
        }
    }

    @Override
    public void setNormal(Path path){
        for(int i=0;i<path.triangles.size();++i){
            if(path.triangles.get(i).isPart(centre)){
                if(i%2==0){
                    d=Vector.Minus(Vector.Plus(
                            path.triangles.get(i+1).getPoint(0),
                            path.triangles.get(i+1).getPoint(2)),
                        Vector.Plus(path.triangles.get(i).getPoint(2),
                            path.triangles.get(i).getPoint(0)));

                }
                else{
                    d=Vector.Minus(Vector.Plus(
                            path.triangles.get(i).getPoint(0),
                            path.triangles.get(i).getPoint(2)),
                        Vector.Plus(path.triangles.get(i-1).getPoint(2),
                            path.triangles.get(i-1).getPoint(0)));
                }
                up=path.triangles.get(i).getNormal();
                d.Multiplication(0.5);d.setY(0);
                break;
            }
        }
        angle=MyMath.RadtoDegree(Math.acos(Geometry.getCosAngle(d,new Vector(0,0,-1))));
    }

    @Override
    public int pickedUp(Vector marble_position){
        Vector marble_move=Vector.Minus(marble_position,last_marble_position);
        Vector _delta=Vector.Minus(marble_position,centre);
        if(Geometry.getCosAngle(marble_move,_delta)>0 && _delta.Length()<1.25){
                last_marble_position.set(marble_position.getX(),
                        marble_position.getY(),marble_position.getZ());
                return availableObjects.pickedup.ordinal();
        }
        else{
            last_marble_position.set(marble_position.getX(),
                    marble_position.getY(),marble_position.getZ());
            return availableObjects.none.ordinal();
        }
    }

    @Override
    public void transform(GL10 gl){
        gl.glTranslatef(centre.getX(),centre.getY()+delta,centre.getZ());
        gl.glRotatef(-angle,0,1,0);
    }

    @Override()
    public void update(){
        if(incr){
            delta+=0.01f;
        }
        else{
            delta-=0.01f;
        }
        if(delta>=0.1f)
            incr=false;
        else if(delta<=-0.1f)
            incr=true;
    }

    @Override
    public void draw(GL10 gl){
        transform(gl);

        OpenGLSystem.enable(gl,OpenGLSystem.CULL_FACE | OpenGLSystem.TEXTURE);
        OpenGLSystem.enableClientStates(gl,OpenGLSystem.NORMAL_ARRAY |
                OpenGLSystem.TEXTURE_ARRAY | OpenGLSystem.VERTEX_ARRAY);

        OpenGLSystem.setMaterial(gl,color);

        int triangles=2*(res_tube+1)*(res/2);
        if(OptionsLibrary.shadow){
            if(flag==1){
                triangles=triangles/2+(int)(triangles*(delta/1.25f));
                flag=0;
            }
            else
                flag=1;
        }

        OpenGLSystem.drawTriangles(gl,texture,rightPointBuffer,rightPointBuffer,
                rightTextureBuffer,triangles,GL10.GL_TRIANGLE_STRIP);
        OpenGLSystem.drawTriangles(gl,texture,leftPointBuffer,leftPointBuffer,
                leftTextureBuffer,triangles,GL10.GL_TRIANGLE_STRIP);
        
        OpenGLSystem.disableClientStates(gl,OpenGLSystem.NORMAL_ARRAY |
                OpenGLSystem.VERTEX_ARRAY | OpenGLSystem.TEXTURE_ARRAY);
        OpenGLSystem.disable(gl,OpenGLSystem.CULL_FACE | OpenGLSystem.TEXTURE);
    }
}
